import pandas as pd
import numpy as np
import datetime
import random
from pyecharts import options as opts
from pyecharts.charts import HeatMap, Page, Line, Grid
from pyecharts.components import Table
from bs4 import BeautifulSoup



def create_heatmap(result_df, label, x_name, y_name):
    mean_val = result_df[f'{label}'].mean()  # 计算该列的均值
    std_val = result_df[f'{label}'].std()  # 计算该列的标准差
    # 定义异常值的上下边界
    lower_bound = mean_val - 3 * std_val
    upper_bound = mean_val + 3 * std_val
    # 异常值怎么处理直接删掉还是用边界值填充
    abnormal_df = result_df[(result_df[f'{label}'] < lower_bound) | (result_df[f'{label}'] > upper_bound)]
    # result_df_cleaned = result_df[(result_df[f'{label}'] >= lower_bound) & (result_df[f'{label}'] <= upper_bound)]
    if not abnormal_df.empty:
        print(f"{label}存在异常值,异常值数量:{len(abnormal_df)}")
    # 将异常值替换为np.nan
    result_df[f'{label}'] = np.where((result_df[f'{label}'] > upper_bound) | (result_df[f'{label}'] < lower_bound), np.nan,
                                 result_df[f'{label}'])
    pivot_df = result_df.pivot_table(
        values=f'{label}',
        index=f'{y_name}',  # Y轴作为行
        columns=f'{x_name}',  # X轴作为列
        aggfunc='mean'  # 处理重复值：取平均值
    )
    rows = len(pivot_df)
    cols = len(pivot_df.columns)
    datas = []
    for i in range(rows):
        for j in range(cols):
            datas.append([j, i , pivot_df.iloc[i, j]])
    if label == "max_drawdown":
        range_color = ["#00FF00", "#FFFF00", "#FF0000"][::-1]  # 绿-黄-红
    else:
        range_color = ["#00FF00", "#FFFF00", "#FF0000"]  # 绿-黄-红
    # 绘制热力图
    heatmap = (
        HeatMap()
        .add_xaxis(pivot_df.columns.tolist())
        .add_yaxis(
            f"{label}",
            pivot_df.index.tolist(),
            datas,
            label_opts=opts.LabelOpts(is_show=False),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title=f"{label}热力图"),
            visualmap_opts=opts.VisualMapOpts(
                min_=result_df[f"{label}"].min(),
                max_=result_df[f"{label}"].max(),
                is_calculable=True,
                range_color=range_color,
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="item",
                axis_pointer_type="cross"
            ),
        )
    )
    return heatmap


def create_data_table(df, title):
    """创建数据表格"""
    # 转换数据为表格格式
    headers = df.columns.tolist()
    rows = []
    for _, row in df.iterrows():
        rows.append([str(x) for x in row.tolist()])

    table = (
        Table()
        .add(headers, rows)
        .set_global_opts(
            title_opts=opts.ComponentTitleOpts(title=title, subtitle="")
        )
    )
    return table


def create_line_chart(df, title, x_label, y_labels, holding_areas, date_length):
    """创建折线图"""
    y_label1, y_label2, y_label3 = tuple(y_labels)
    line = (
        Line(init_opts=opts.InitOpts(width="90%"))
        .add_xaxis(df[x_label].tolist())
        .add_yaxis(f"nav", df[y_label1].tolist(),
                  is_smooth=True,
                  label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis(f"nav_after_fee", df[y_label2].tolist(),
                   is_smooth=True,
                   label_opts=opts.LabelOpts(is_show=False))
        .add_yaxis("hold_btc", df[y_label3].tolist(),
                  is_smooth=True,
                  label_opts=opts.LabelOpts(is_show=False))
        # .add_yaxis("ma", df[y_label4].tolist(),
        #            is_smooth=True,
        #            label_opts=opts.LabelOpts(is_show=False))
        # .add_yaxis("up", df[y_label5].tolist(),
        #            is_smooth=True,
        #            label_opts=opts.LabelOpts(is_show=False))
        # .add_yaxis("down", df[y_label6].tolist(),
        #            is_smooth=True,
        #            label_opts=opts.LabelOpts(is_show=False))
        # .set_series_opts(
        #     markarea_opts=opts.MarkAreaOpts(data=holding_areas)
        # )
        .add_yaxis(
            series_name="holding",
            y_axis=[None] * date_length,  # 空数据，只用于显示背景
            markarea_opts=opts.MarkAreaOpts(data=holding_areas),
            itemstyle_opts=opts.ItemStyleOpts(opacity=0),  # 隐藏线条
            label_opts=opts.LabelOpts(is_show=False),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title=title),
            datazoom_opts=opts.DataZoomOpts(
                type_="inside",  # 组件类型：'slider' 或 'inside'
            ),  # 添加数据缩放组件
            tooltip_opts=opts.TooltipOpts(trigger="axis"),
            yaxis_opts=opts.AxisOpts(
                axislabel_opts=opts.LabelOpts(formatter="{value}")
            )
        )
    )
    return line


def gen_html(frequency, begin_date, x_name, y_name, last_date="2025-08-31"):
    path = f"{frequency}/{begin_date}/result/backtest_performance.csv"
    result_df = pd.read_csv(path)
    page = Page(layout=Page.SimplePageLayout)
    from backtest_boll_breakup_with_dif_ema_atr import Performance
    for label in Performance.get_all_columns():
        heatmap = create_heatmap(result_df.copy(), label, x_name, y_name)
        page.add(heatmap)
    for table_name in Performance.get_columns_for_line_chart():
        table_df = result_df.sort_values(by=table_name, ascending=False)
        # 取最高的两个值
        table_df = table_df[:2]
        count = 0
        for _, row in table_df.iterrows():
            count +=1
            m = int(row[f'{x_name}'])
            n = row[f'{y_name}']
            trade_log_df = pd.read_csv(f'{frequency}/{begin_date}/trade_log/trade_log_{m}_{n}.csv')
            holding_areas = []
            if not trade_log_df.empty and trade_log_df.iloc[0]['action'] == "SELL":
                begin_datetime = datetime.datetime.strptime(begin_date, "%Y%m%d").date()
                holding_areas.append(
                    [
                        {"xAxis": begin_datetime.strftime("%Y-%m-%d"), "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}},
                        {"xAxis": trade_log_df.iloc[0]["date"], "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}}
                    ]
                )
                trade_log_df = trade_log_df[1:]
            for i in range(0, len(trade_log_df), 2):
                start_date = trade_log_df.iloc[i]["date"]
                assert trade_log_df.iloc[i]['action'] == "BUY"
                if i + 1 >= len(trade_log_df):
                    end_date = last_date
                else:
                    end_date = trade_log_df.iloc[i + 1]["date"]
                holding_areas.append(
                    [
                        {"xAxis": start_date, "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}},
                        {"xAxis": end_date, "itemStyle": {"color": "rgba(235, 241, 222, 0.4)"}}
                    ]
                )
            path = f"{frequency}/{begin_date}/nav/nav_{m}_{n}.csv"
            nav_df = pd.read_csv(path)
            # y_labels = [f"nav0", "nav2", "nav(hold_btc)", "ma", "up", "down"]
            y_labels = [f"nav0", "nav2", "nav(hold_btc)"]
            line = create_line_chart(nav_df, f"{x_name}={m},{y_name}={n}净值曲线({table_name}_top{count})", "date",
                                     y_labels, holding_areas, len(nav_df))
            page.add(line)
            table = Table()
            table.add(["指标", "值"],[[idx, val] for idx, val in row.items()])
            page.add(table)
            path = f"{frequency}/backtest_performance_by_year.csv"
            performance_by_year = pd.read_csv(path)
            performance_by_year = performance_by_year[(performance_by_year[f"{x_name}"] == m) & (performance_by_year[f"{y_name}"] == n)]
            performance_by_year = performance_by_year[performance_by_year["year"] >= int(begin_date[:4])]
            columns = ["year", f"{x_name}", f"{y_name}"] + Performance.get_columns_for_annual_display()
            tabel = create_data_table(performance_by_year[columns], "年度表现")
            page.add(tabel)

    # 生成并保存
    html_path = f"{frequency}/{begin_date}/{frequency}_{begin_date}.html"
    page.render(html_path)
    with open(html_path, 'r', encoding='utf-8') as f:
        html_content = f.read()

    # 使用BeautifulSoup解析
    soup = BeautifulSoup(html_content, 'html.parser')

    # 1. 为表格容器添加样式
    chart_containers = soup.find_all(class_='chart-container')
    for container in chart_containers:
        if container.has_attr('style'):
            container['style'] += 'overflow-x: auto;'
        else:
            container['style'] = 'overflow-x: auto;'
    # 保存修改后的HTML
    with open(html_path, 'w', encoding='utf-8') as file:
        file.write(str(soup))


if __name__ == '__main__':
    gen_html("1d", "20170101", "M", "N", "2025-08-31")
    # for frequency in ["1d", "3h", "1h"]:
    #     for begin_date in ["20170101", "20200101", "20230101"]:
    #         gen_html(frequency, begin_date, "M", "N", "2025-08-31")
